//
//  TRTCLiveRoom.m
//  TRTCVoiceRoomOCDemo
//
//  Created by abyyxwang on 2020/7/7.
//  Copyright © 2020 tencent. All rights reserved.
//

#import "TRTCLiveRoom.h"
#import "TRTCLiveRoomMemberManager.h"
#import "TRTCLiveRoomModelDef.h"
#import "TXLiveRoomCommonDef.h"
#import "TRTCLiveRoomIMAction.h"
#import "TRTCCloudAnction.h"
#import <ImSDK/ImSDK.h>
#import "TRTCLiveRoomEduBoard.h"

static double trtcLiveSendMsgTimeOut = 15;
static double trtcLiveHandleMsgTimeOut = 10;
static double trtcLiveCheckStatusTimeOut = 3;

@interface NSNumber (String)

- (BOOL)isEqualToString:(NSString *)string;

@end

@implementation NSNumber (String)

- (BOOL)isEqualToString:(NSString *)string {
    return NO;
}

@end

@interface TRTCLiveRoom () <TRTCLiveRoomMembermanagerDelegate, V2TIMAdvancedMsgListener, V2TIMGroupListener,TRTCLiveRoomEduBoardDelegate>

@property (nonatomic, strong) TRTCLiveRoomEduBoard *eduBoard;
@property (nonatomic, strong) TRTCCloudAnction *trtcAction;
@property (nonatomic, strong) TRTCLiveRoomMemberManager *memberManager;
@property (nonatomic, strong) TRTCLiveRoomConfig *config;
@property (nonatomic, strong) TRTCLiveUserInfo *me;
@property (nonatomic, assign) BOOL mixingInviteAnchorStream; // PK是否混流
@property (nonatomic, assign) BOOL mixingLinkMicStream; // 连麦是否混流
@property (nonatomic, strong) TRTCLiveRoomInfo *curRoomInfo;

@property (nonatomic, strong, readonly) TXBeautyManager *beautyManager;
@property (nonatomic, assign) TRTCLiveRoomLiveStatus status;

@property (nonatomic, strong, readonly) NSString *roomID;
@property (nonatomic, strong, readonly) NSString *ownerId;

@property (nonatomic, copy) Callback enterRoomCallback;
@property (nonatomic, copy) Callback exitRoomCallback;
@property (nonatomic, copy) ResponseCallback requestJoinAnchorCallback;
@property (nonatomic, copy) ResponseCallback requesInviteAnchorCallback;

@property (nonatomic, strong) TRTCJoinAnchorInfo *joinAnchorInfo;
@property (nonatomic, strong) TRTCInviteAnchorInfo *inviteAnchorInfo;

@property (nonatomic, assign, readonly) BOOL isOwner; // 主持人
@property (nonatomic, assign, readonly) BOOL isAnchor; // 主讲人
@property (nonatomic, assign, readonly) BOOL isOnMic; // 标记观众是否上麦
@property (nonatomic, assign, readonly) BOOL configCdn;
@property (nonatomic, assign, readonly) BOOL shouldPlayCdn;
@property (nonatomic, assign, readonly) BOOL shouldMixStream;


@end

@implementation TRTCLiveRoom

+ (instancetype)shareInstance {
    static TRTCLiveRoom *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[TRTCLiveRoom alloc] init];
    });
    return instance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.memberManager.delegate = self;
    }
    return self;
}

- (void)dealloc {
    TRTCLog(@"dealloc TRTCLiveRoom");
}

#pragma mark - 懒加载&&只读属性
-(TRTCLiveRoomEduBoard *)eduBoard{
    if (!_eduBoard) {
        _eduBoard = [[TRTCLiveRoomEduBoard alloc] init];
    }
    return _eduBoard;
}
- (TRTCCloudAnction *)trtcAction {
    if (!_trtcAction) {
        _trtcAction = [[TRTCCloudAnction alloc] init];
    }
    return _trtcAction;
}

- (TRTCLiveRoomMemberManager *)memberManager {
    if (!_memberManager) {
        _memberManager = [[TRTCLiveRoomMemberManager alloc] init];
    }
    return _memberManager;
}
- (TRTCInviteAnchorInfo *)inviteAnchorInfo{
    if (!_inviteAnchorInfo) {
        _inviteAnchorInfo = [[TRTCInviteAnchorInfo alloc] init];
    }
    return _inviteAnchorInfo;
}

-(TRTCJoinAnchorInfo *)joinAnchorInfo {
    if (!_joinAnchorInfo) {
        _joinAnchorInfo = [[TRTCJoinAnchorInfo alloc] init];
    }
    return _joinAnchorInfo;
}

- (NSString *)roomID {
    return self.trtcAction.roomId;
}

- (NSString *)ownerId {
    return self.memberManager.ownerId;
}

- (TXBeautyManager *)beautyManager {
    return self.trtcAction.beautyManager;
}

- (void)setStatus:(TRTCLiveRoomLiveStatus)status {
    if (_status != status) {
        if (self.curRoomInfo) {
            self.curRoomInfo.roomStatus = status;
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRoomInfoChange:)]) {
                [self.delegate trtcLiveRoom:self onRoomInfoChange:self.curRoomInfo];
            }
        } else {
            NSString *streameUrl = [NSString stringWithFormat:@"%@_stream", self.me.userId];
            TRTCLiveRoomInfo* roomInfo = [[TRTCLiveRoomInfo alloc] initWithRoomId:self.roomID
                                                                         roomName:@""
                                                                         coverUrl:@""
                                                                          ownerId:self.me.userId ?: @""
                                                                        ownerName:self.me.userName ?: @""
                                                                        streamUrl:streameUrl
                                                                      memberCount:self.memberManager.audience.count
                                                                       roomStatus:status];
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRoomInfoChange:)]) {
                [self.delegate trtcLiveRoom:self onRoomInfoChange:roomInfo];
            }
        }
    }
    _status = status;
}


#pragma mark - public method

#pragma mark - 用户
- (void)loginWithSdkAppID:(int)sdkAppID user:(TRTCLiveUserInfo *)user userSig:(NSString *)userSig config:(TRTCLiveRoomConfig *)config callback:(Callback)callback
{
    @weakify(self)
    [TRTCLiveRoomIMAction loginWithUserID:user.userId userSig:userSig callback:^(int code, NSString * _Nonnull message) {
        @strongify(self)
        if (!self) {
            return;
        }
        if (code == 0) {
            self.me = user;
            self.config = config;
            if (self.me.isOwner) {
                [self.memberManager setOwner:self.me];
            }
            [TRTCLiveRoomIMAction addMessageLister:self];
            [self.trtcAction setupWithUserId:user.userId urlDomain:config.cdnPlayDomain sdkAppId:sdkAppID userSig:userSig];
            [self.eduBoard setupSDKWithSDKAppID:sdkAppID userSig:userSig userID:user.userId];
        }
        if (callback) {
            callback(0, @"login success.");
        }
    }];
}

- (void)logout:(Callback)callback {
    @weakify(self)
    [TRTCLiveRoomIMAction logout:^(int code, NSString * _Nonnull message) {
        @strongify(self)
        if (!self) {
            return;
        }
        self.me = nil;
        self.config = nil;
        [self.trtcAction reset];
        if (callback) {
            callback(code, message);
        }
        [TRTCLiveRoomIMAction releaseSdk];
    }];
}

- (void)setSelfProfileWithName:(NSString *)name avatarURL:(NSString *)avatarURL callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    me.avatarURL = avatarURL;
    me.userName = name;
    @weakify(self)
    [TRTCLiveRoomIMAction setProfileWithName:name avatar:avatarURL callback:^(int code, NSString * _Nonnull message) {
        @strongify(self)
        if (!self) {
            return;
        }
        if (code == 0) {
            [self.memberManager updateProfile:me.userId name:name avatar:avatarURL];
        }
        if (callback) {
            callback(code, message);
        }
    }];
}

- (void)createRoomWithRoomID:(UInt32)roomID roomParam:(TRTCCreateRoomParam *)roomParam callback:(Callback)callback {
    [TRTCCloud sharedInstance].delegate = self;
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    BOOL result = [self checkRoomUnjoined:callback];
    if (!result) {
        return;
    }
    NSString *roomIDStr = [NSString stringWithFormat:@"%d", roomID];
    self.curRoomInfo = [[TRTCLiveRoomInfo alloc] initWithRoomId:roomIDStr
                                                       roomName:roomParam.roomName
                                                       coverUrl:roomParam.coverUrl
                                                        ownerId:me.userId
                                                      ownerName:me.userName
                                                      streamUrl:[NSString stringWithFormat:@"%@_stream", me.userId]
                                                    memberCount:0
                                                     roomStatus:TRTCLiveRoomLiveStatusSingle];
    @weakify(self)
    [TRTCLiveRoomIMAction createRoomWithRoomID:roomIDStr
                                     roomParam:roomParam success:^(NSArray<TRTCLiveUserInfo *> * _Nonnull members, NSDictionary<NSString *,id> * _Nonnull customInfo, TRTCLiveRoomInfo * _Nullable roomInfo) {
        @strongify(self)
        if (!self) {
            return;
        }
        self.status = TRTCLiveRoomLiveStatusSingle;
        self.trtcAction.roomId = roomIDStr;
        [self.memberManager setmembers:members groupInfo:customInfo];
        [self.memberManager setOwner:me];
        if (callback) {
            callback(0, @"");
        }
    } error:callback];
}

- (void)destroyRoom:(Callback)callback {
    TRTCLiveUserInfo *user = [self checkUserLogIned:callback];
    if (!user) {
        return;
    }
    NSString *roomId = [self checkRoomJoined:callback];
    if (!roomId) {
        return;
    }
    if (![self checkIsOwner:callback]) {
        return;
    }
    [self reset];
    [TRTCLiveRoomIMAction destroyRoomWithRoomID:roomId callback:callback];
}

- (void)enterRoomWithRoomID:(UInt32)roomID isAudience:(BOOL)isAudience callback:(Callback)callback {
    [TRTCCloud sharedInstance].delegate = self;
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    if (![self checkRoomUnjoined:callback]) {
        return;
    }
    NSString *roomIDStr = [NSString stringWithFormat:@"%d", roomID];
    self.trtcAction.roomId = roomIDStr;
    if (self.shouldPlayCdn) {
        [self imEnter:roomIDStr callback:callback];
    } else {
        [self trtcEnter:roomIDStr userId:me.userId isAudience:isAudience callback:callback];
        @weakify(self)
        [self imEnter:roomIDStr callback:^(int code, NSString * _Nullable message) {
            @strongify(self)
            if (!self) {
                return;
            }
            if (code != 0 && [self canDelegateResponseMethod:@selector(trtcLiveRoom:onError:message:)]) {
                [self.delegate trtcLiveRoom:self onError:code message:message];
            }
        }];
    }
}

- (void)imEnter:(NSString *)roomID callback:(Callback)callback {
    @weakify(self)
    [TRTCLiveRoomIMAction enterRoomWithRoomID:roomID success:^(NSArray<TRTCLiveUserInfo *> * _Nonnull members, NSDictionary<NSString *,id> * _Nonnull customInfo, TRTCLiveRoomInfo * _Nullable roomInfo) {
        @strongify(self)
        if (!self) {
            return;
        }
        [self setSelfProfileWithName:[[ACUserProfileManager shareInstance] userModel].nickname avatarURL:[[ACUserProfileManager shareInstance] userModel].avatar callback:^(int code, NSString * _Nullable message) {
            
        }];
        [self.memberManager setmembers:members groupInfo:customInfo];
        self.curRoomInfo = roomInfo;
        self.status = roomInfo != nil ? roomInfo.roomStatus : TRTCLiveRoomLiveStatusSingle;
        if (callback) {
            callback(0, @"");
        }
        if (self.shouldPlayCdn) {
            [self notifyAvailableStreams];
        }
    } error:callback];
}

- (void)trtcEnter:(NSString *)roomID userId:(NSString *)userId isAudience:(BOOL)isAudience callback:(Callback)callback {
    self.trtcAction.roomId = roomID;
    self.enterRoomCallback = callback;
    if (isAudience) {
        [self.trtcAction enterRoomWithRoomID:roomID userId:userId role:TRTCRoleAudience];
    }else{
        [self.trtcAction enterRoomWithRoomID:roomID userId:userId role:TRTCRoleAnchor];
    }
    NSString *uuid = [self.trtcAction.curroomUUID mutableCopy];
    @weakify(self)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        @strongify(self)
        if (!self) {
            return;
        }
        if ([uuid isEqualToString:self.trtcAction.curroomUUID] && self.enterRoomCallback) {
            self.enterRoomCallback(-1, @"enterRoom 请求超时");
            self.enterRoomCallback = nil;
        }
    });
}

- (void)exitRoom:(Callback)callback {
    if (![self checkUserLogIned:callback]) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    if (self.isOwner) {
        if (callback) {
            callback(-1, @"只有普通成员才能退房");
        }
        return;
    }
    self.exitRoomCallback = callback;
    [self reset];
    [TRTCLiveRoomIMAction exitRoomWithRoomID:roomID callback:callback];
}

- (void)getRoomInfosWithRoomIDs:(NSArray<NSNumber *> *)roomIDs callback:(RoomInfoCallback)callback {
    NSMutableArray *strRoomIds = [[NSMutableArray alloc] initWithCapacity:2];
    [roomIDs enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString* str = [obj stringValue];
        [strRoomIds addObject:str];
    }];
    [TRTCLiveRoomIMAction getRoomInfoWithRoomIds:strRoomIds success:^(NSArray<TRTCLiveRoomInfo *> * _Nonnull roomInfos) {
        NSMutableArray *sortInfo = [[NSMutableArray alloc] initWithCapacity:2];
        NSMutableDictionary *resultMap = [[NSMutableDictionary alloc] initWithCapacity:2];
        for (TRTCLiveRoomInfo *room in roomInfos) {
            resultMap[room.roomId] = room;
        }
        for (NSString *roomId in strRoomIds) {
            if ([resultMap.allKeys containsObject:roomId]) {
                TRTCLiveRoomInfo *roomInfo = resultMap[roomId];
                if (roomInfo) {
                    [sortInfo addObject:roomInfo];
                }
            }
        }
        if (callback) {
            callback(0, @"success", sortInfo);
        }
    } error:^(int code, NSString * _Nonnull message) {
        if (callback) {
            callback(code, message, @[]);
        }
    }];
}

- (void)getAnchorList:(UserListCallback)callback {
    if (callback) {
        callback(0, @"", self.memberManager.anchors.allValues);
    }
}

- (void)getAudienceList:(UserListCallback)callback {
    NSString *roomId = [self checkRoomJoined:^(int code, NSString * _Nullable message) {
        
    }];
    if (!roomId) {
        if (callback) {
            callback(-1, @"没有进入房间", self.memberManager.audience);
        }
        return;
    }
    @weakify(self)
    [TRTCLiveRoomIMAction getAllMembersWithRoomID:roomId success:^(NSArray<TRTCLiveUserInfo *> * _Nonnull members) {
        @strongify(self)
        if (!self) {
            return;
        }
        for (TRTCLiveUserInfo *user in members) {
            if (!self.memberManager.anchors[user.userId] && ![user.userId startsWith:@"tic_push_user"]) {
                [self.memberManager addAudience:user];
            }
        }
        if (callback) {
            callback(0, @"", self.memberManager.audience);
        }
    } error:^(int code, NSString * _Nonnull message) {
        @strongify(self)
        if (!self) {
            return;
        }
        if (callback) {
            callback(0, @"", self.memberManager.audience);
        }
    }];
}
- (void)JoinAnchorStartToPublish{
    [self.trtcAction joinAnchorStartPublish];
}
-(void)JoinAnchorStopToPublish{
    [self.trtcAction joinAnchorStopPublisn];
}
- (void)startCameraPreviewWithFrontCamera:(BOOL)frontCamera view:(UIView *)view callback:(Callback)callback {
    if (![self checkUserLogIned:callback]) {
        return;
    }
    [self.trtcAction startLocalPreview:frontCamera view:view];
    callback(0, @"success");
}
- (void)stopCameraPreview {
    [self.trtcAction stopLocalPreview];
}
-(void)startRemoteView:(NSString *)anchorID View:(UIView *)view{
    if (anchorID != self.me.userId) {
        [self.trtcAction startRemoteView:anchorID View:view];
    }
}
-(void)stopRemoteView:(NSString *)anchorID{
    if (anchorID != self.me.userId) {
        [self.trtcAction stopRemoteView:anchorID];
    }
}

-(void)stopToAnchor{
    [self stopCameraPreview];
    [self.trtcAction stopPublish];
    [self stopToAnchor:self.me.userId];
}

- (void)startPublishWithStreamID:(NSString *)streamID callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [self.trtcAction setupVideoParam:self.isOwner];
    [self.trtcAction startPublish:streamID];
    NSString *streamIDNonnull = ([streamID isEqualToString:@""] || !streamID) ? [self.trtcAction cdnUrlForUser:me.userId roomId:roomID] : streamID;
    if (self.isOwner) {
        [self.memberManager addAnchor:me];
        [self.memberManager updateStream:me.userId streamId:streamIDNonnull];
        if (callback) {
            callback(0, @"");
        }
    } else if (self.ownerId) {
        [self.trtcAction switchRole:TRTCRoleAnchor];
    } else {
        NSAssert(NO, @"");
    }
}

-(void)notifiAudienceStreamChangedToOwerWithStreamID:(NSString *)streamID callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    NSString *streamIDNonnull = ([streamID isEqualToString:@""] || !streamID) ? [self.trtcAction cdnUrlForUser:me.userId roomId:roomID] : streamID;
    [TRTCLiveRoomIMAction notifyStreamToAnchorWithUserId:self.ownerId RoomID:self.roomID streamID:streamIDNonnull callback:callback];
}

-(void)anchorStartPublishcallback:(Callback)callback  {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [self.trtcAction setupVideoParam:self.isOwner];
    [self.trtcAction anchorStartPublish];
    [self.memberManager addAnchor:me];
    [self.memberManager updateStream:me.userId streamId:self.me.userId];
    if (callback) {
        callback(0, @"");
    }
}
- (void)stopPublish:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [self.trtcAction stopPublish];
    [self.memberManager updateStream:me.userId streamId:nil];
    if (self.isOwner) {
        [self.trtcAction exitRoom];
    } else {
        // 观众结束连麦
        [self stopCameraPreview];
        [self switchRole:NO];
    }
}

- (void)startPlayWithUserID:(NSString *)userID view:(UIView *)view callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
//    TRTCLiveUserInfo *user = self.memberManager.pkAnchor;
//    NSString *pkAnchorRoomId = self.pkAnchorInfo.roomId;
//    if (user && pkAnchorRoomId) {
//        [self.trtcAction startPlay:user.userId streamID:user.streamId view:view usesCDN:self.shouldPlayCdn roomId:pkAnchorRoomId callback:callback];
//    } else
    if (self.memberManager.anchors[userID]) {
        TRTCLiveUserInfo *anchor = self.memberManager.anchors[userID];
        [self.trtcAction startPlay:anchor.userId streamID:anchor.streamId view:view usesCDN:self.shouldPlayCdn roomId:nil callback:callback];
    } else {
        if (callback) {
            callback(-1, @"未找到该主播");
        }
    }
}

- (void)stopPlayWithUserID:(NSString *)userID callback:(Callback)callback {
    if (!userID) {
        callback(-1, @"user id is nil");
        return;
    }
    [self.trtcAction stopPlay:userID usesCDN:self.shouldPlayCdn];
    if (callback) {
        callback(0, @"");
    }
}
#pragma mark - 观众申请连麦

- (void)requestJoinAnchor:(NSString *)reason responseCallback:(ResponseCallback)responseCallback {
    if (!responseCallback) {
        responseCallback = ^(BOOL reslut, NSString *msg) {};
    }
    TRTCLiveUserInfo *me = [self checkUserLogIned:nil];
    if (!me) {
        responseCallback(NO, @"还未登录");
        return;
    }
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        responseCallback(NO, @"没有进入房间");
        return;
    }
    if (self.isOnMic) {
        responseCallback(NO, @"当前已经是连麦状态");
        return;
    }
    if (self.joinAnchorInfo.userId) {
        responseCallback(NO, @"当前用户正在等待连麦回复");
        return;
    }
//    if (self.status == TRTCLiveRoomLiveStatusNone) {
//        responseCallback(NO, @"出错请稍后尝试");
//        return;
//    }

    if (!self.ownerId) {
        return;
    }
    self.requestJoinAnchorCallback = responseCallback;
    self.joinAnchorInfo.userId = me.userId ?: @"";
    self.joinAnchorInfo.uuid = [[NSUUID UUID] UUIDString];
    [TRTCLiveRoomIMAction requestJoinAnchorWithUserID:self.ownerId reason:reason callback:^(int code, NSString * _Nonnull message) {
        if (code != 0) {
            if (responseCallback) {
                responseCallback(NO, message);
            }
        }
    }];
   
}

- (void)responseJoinAnchor:(NSString *)userID agree:(BOOL)agree reason:(NSString *)reason {
    self.joinAnchorInfo.userId = userID;
    self.joinAnchorInfo.uuid = [[NSUUID UUID] UUIDString];
    
    TRTCLiveUserInfo *me = [self checkUserLogIned:nil];
    if (!me && !self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        return;
    }
    if ([TRTCCloud sharedInstance].delegate != self) {
        [TRTCCloud sharedInstance].delegate = self;
    }
    if ([self.joinAnchorInfo.userId isEqualToString:userID]) {
        self.joinAnchorInfo.isResponsed = YES;
    }
    [TRTCLiveRoomIMAction respondJoinAnchorWithUserID:userID agreed:agree reason:reason callback:nil];
}

- (void)kickoutJoinAnchor:(NSString *)userID callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me && !self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
//    if (!self.memberManager.anchors[userID]) {
//        if (callback) {
//            callback(-1, @"该用户尚未连麦");
//        }
//        return;
//    }
    [self.memberManager removeRequestJoinAnchor:userID];
    [TRTCLiveRoomIMAction kickoutJoinAnchorWithUserID:userID callback:callback];
    [self stopToAnchor:userID];
}

- (void)quitJoinAnchor:(NSString *)userID callback:(Callback _Nullable)callback{
    // userID  主持人  当前用户主动退出 me.userId
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me && !self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    if (!self.memberManager.anchors[me.userId]) {
        if (callback) {
            callback(-1, @"该用户尚未连麦");
        }
        return;
    }
    [self.memberManager removeRequestJoinAnchor:me.userId];
    [TRTCLiveRoomIMAction quitJoinAnchorWithUserID:userID callback:callback];
    [self stopCameraPreview];
    [self switchRole:NO];
    [self stopToAnchor:me.userId];
    [self clearJoinState:YES];
}

#pragma mark - 主持人邀请主讲人

- (void)requestInviteAnchor:(NSString *)userID responseCallback:(ResponseCallback _Nullable)responseCallback{
    if (!responseCallback) {
        responseCallback = ^(BOOL reslut, NSString *msg) {};
    }
    TRTCLiveUserInfo *me = [self checkUserLogIned:nil];
    if (!me) {
        responseCallback(NO, @"还未登录");
        return;
    }
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        responseCallback(NO, @"没有进入房间");
        return;
    }
    if (self.memberManager.anchors[userID]) {
        responseCallback(NO, @"已经在麦上了");
        return;
    }
    if (self.inviteAnchorInfo.userId) {
        responseCallback(NO, @"当前用户正在等待连麦回复");
        return;
    }
//    if (self.status == TRTCLiveRoomLiveStatusNone) {
//        responseCallback(NO, @"出错请稍后尝试");
//        return;
//    }
    if (!self.ownerId) {
        return;
    }
    self.inviteAnchorInfo.userId = userID;
    self.inviteAnchorInfo.uuid = [[NSUUID UUID] UUIDString];
    [TRTCLiveRoomIMAction requestInviteAnchorWithUserID:userID callback:^(int code, NSString * _Nonnull message) {
        if (code != 0) {
            if (responseCallback) {
                responseCallback(NO, message);
            }
        }
    }];
}

/// 响应主持人的邀请
/// - Parameters:
///   - userID 主持人ID
///   - agreed  true：同意；false：拒绝
///   - callback 操作回调
/// - Note: 被邀请观众回复后，主持人会收到。。。。
- (void)respondInviteAnchor:(NSString *)userID agreed:(BOOL)agreed callback:(Callback _Nullable)callback{
    TRTCLiveUserInfo *me = [self checkUserLogIned:nil];
    if (!me && !self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        return;
    }
//    if ([self.inviteAnchorInfo.userId isEqualToString:userID]) {
//        [self switchRole:YES];
        self.inviteAnchorInfo.isResponsed = YES;
//    }
    
    if ([TRTCCloud sharedInstance].delegate != self) {
        [TRTCCloud sharedInstance].delegate = self;
    }
    [TRTCLiveRoomIMAction respondInviteAnchorWithUserID:userID agreed:agreed callback:callback];
}


- (void)quitInviteAnchor:(NSString *)userID callback:(Callback _Nullable)callback{
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [self stopCameraPreview];
    [self stopToAnchor:me.userId];
//    [self switchRole:NO];
    [self clearInviteState];
//    if (self.status == TRTCLiveRoomLiveStatusInviteAnchor && self.memberManager.inviteAnchor) {
//        [self.inviteAnchorInfo reset];
//        self.status = TRTCLiveRoomLiveStatusSingle;
//        [self.memberManager removeAnchor:self.memberManager.pkAnchor.userId];
        [TRTCLiveRoomIMAction quitInviteAnchorWithUserID:userID callback:callback];
//    } else {
//        if (callback) {
//            callback(-1, @"当前不是有主讲状态");
//        }
//    }
}

/// 主讲人被主持人踢出主讲
/// - Parameters:
///   - userID 主讲人ID
///   - callback 操作回调
/// - Note: 主讲人被主持人踢出之后，主讲人会收到回调。。。
- (void)kickoutInviteAnchor:(NSString *)userID callback:(Callback _Nullable)callback{
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [self stopToAnchor:userID];
    [TRTCLiveRoomIMAction kickoutInviteAnchorWithUserID: self.inviteAnchorInfo.userId callback:callback];
    [self clearInviteState];
}

#pragma mark - 音频设置
- (void)switchCamera {
    [[TRTCCloud sharedInstance] switchCamera];
}

- (void)setMirror:(BOOL)isMirror {
    [[TRTCCloud sharedInstance] setVideoEncoderMirror:isMirror];
}

- (void)muteLocalAudio:(BOOL)isMuted {
    [[TRTCCloud sharedInstance] muteLocalAudio:isMuted];
}

-(void)muteLocalVideo:(BOOL)isMute{
    [[TRTCCloud sharedInstance] muteLocalVideo:isMute];
}
- (void)muteRemoteAudioWithUserID:(NSString *)userID isMuted:(BOOL)isMuted {
    [[TRTCCloud sharedInstance] muteRemoteAudio:userID mute:isMuted];
}

- (void)muteAllRemoteAudio:(BOOL)isMuted {
    [[TRTCCloud sharedInstance] muteAllRemoteAudio:isMuted];
}

- (void)setAudioQuality:(NSInteger)quality {
    if (quality == 3) {
        [[TRTCCloud sharedInstance] setAudioQuality:TRTCAudioQualityMusic];
    } else if (quality == 2) {
        [[TRTCCloud sharedInstance] setAudioQuality:TRTCAudioQualityDefault];
    } else {
        [[TRTCCloud sharedInstance] setAudioQuality:TRTCAudioQualitySpeech];
    }
}

- (void)showVideoDebugLog:(BOOL)isShow {
    [[TRTCCloud sharedInstance] showDebugView:isShow ? 2 : 0];
}

#pragma mark - 发送消息
- (void)sendRoomTextMsg:(NSString *)message callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [TRTCLiveRoomIMAction sendRoomTextMsgWithRoomID:roomID message:message callback:callback];
}

- (void)sendRoomCustomMsgWithCommand:(NSString *)cmd message:(NSString *)message callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [TRTCLiveRoomIMAction sendRoomCustomMsgWithRoomID:roomID command:cmd message:message callback:callback];
}
- (void)setGroupMemberMuteWithTime:(uint32_t)seconds userID:(NSString *)userID callback:(Callback)callback {
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me && !self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [TRTCLiveRoomIMAction setGroupMemberMuteWithTime:seconds userID:userID roomID:roomID callback:callback];
}
- (void)kickoutAudienceWithUserID:(NSString *)userID callback:(Callback)callback{
    TRTCLiveUserInfo *me = [self checkUserLogIned:callback];
    if (!me && !self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:callback];
    if (!roomID) {
        return;
    }
    [TRTCLiveRoomIMAction kickoutAudienceWithRoomID:roomID userID:userID callback:callback];
}
- (TXBeautyManager *)getBeautyManager {
    return self.beautyManager;
}

- (TXAudioEffectManager *)getAudioEffectManager {
    return [[TRTCCloud sharedInstance] getAudioEffectManager];
}

#pragma mark - private method
- (BOOL)canDelegateResponseMethod:(SEL)method {
    return self.delegate && [self.delegate respondsToSelector:method];
}

#pragma mark - TRTCCloudDelegate
- (void)onError:(TXLiteAVError)errCode errMsg:(NSString *)errMsg extInfo:(NSDictionary *)extInfo {
    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onError:message:)]) {
        [self.delegate trtcLiveRoom:self onError:errCode message:errMsg];
    }
}

- (void)onWarning:(TXLiteAVWarning)warningCode warningMsg:(NSString *)warningMsg extInfo:(NSDictionary *)extInfo {
    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onWarning:message:)]) {
        [self.delegate trtcLiveRoom:self onWarning:warningCode message:warningMsg];
    }
}
-(void)onExitRoom:(NSInteger)reason{
    if (self.exitRoomCallback) {
        self.exitRoomCallback(0, @"success");
        self.exitRoomCallback = nil;
    }
}
- (void)onEnterRoom:(NSInteger)result {
    [self logApi:@"onEnterRoom", nil];
    if (result < 1) {
        DDLogInfo(@"-----------onenterRoom:%ld",(long)result);
    }
    if (self.enterRoomCallback) {
        self.enterRoomCallback(0, @"success");
        self.enterRoomCallback = nil;
    }
}
-(void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available{
    if (available) {// 主播进来
        if (self.isOwner) {
            if ([self.memberManager.inviteAnchor.userId isEqualToString:userId]) {
                self.status = TRTCLiveRoomLiveStatusInviteAnchor;
                [self.memberManager confirmInviteAnchor:userId];
            } else if (!self.memberManager.anchors[userId]) {
                self.status = TRTCLiveRoomLiveStatusLinkMic;
                [self addTempAnchor:userId];
            }
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
                [self.delegate trtcLiveRoom:self onAnchorEnter:userId];
            }
            [self.trtcAction updateMixingParams:self.shouldMixStream];
        } else {
            if (!self.memberManager.anchors[userId]) {
                [self addTempAnchor:userId];
            }
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
                [self.delegate trtcLiveRoom:self onAnchorEnter:userId];
            }
        }
    }else{ // 主播离开
        if (self.isOwner) {
            if (self.memberManager.anchors[userId] && self.memberManager.anchors.count <= 2) {
                if (self.inviteAnchorInfo.userId && self.inviteAnchorInfo.userId == userId) {
                    if ([self canDelegateResponseMethod:@selector(trtcLiveRoomOnQuitInviteAnchor:)]) {
                        [self.delegate trtcLiveRoomOnQuitInviteAnchor:self];
                    }
                }
                [self clearInviteState];
                [self clearJoinState];
                self.status = TRTCLiveRoomLiveStatusSingle;
            }
            [self.memberManager removeAnchor:userId];
        }
        
        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorExit:)]) {
            [self.delegate trtcLiveRoom:self onAnchorExit:userId];
        }
        if (self.isOwner) {
            [self.trtcAction updateMixingParams:self.shouldMixStream];
        }
    }
}
- (void)onRemoteUserEnterRoom:(NSString *)userId {
//    if (self.shouldPlayCdn) {
//        return;
//    }
//    if ([self.joinAnchorInfo.userId isEqualToString:userId]) {
//        [self clearJoinState:NO];
//    }
//    if ([self.trtcAction isUserPlaying:userId]) {
//        [self.trtcAction startTRTCPlay:userId];
//        return;
//    }
//    if (self.isOwner) {
//        if ([self.memberManager.inviteAnchor.userId isEqualToString:userId]) {
//            self.status = TRTCLiveRoomLiveStatusInviteAnchor;
//            [self.memberManager confirmInviteAnchor:userId];
//        } else if (!self.memberManager.anchors[userId]) {
//            self.status = TRTCLiveRoomLiveStatusLinkMic;
//            [self addTempAnchor:userId];
//        }
//        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
//            [self.delegate trtcLiveRoom:self onAnchorEnter:userId];
//        }
//        [self.trtcAction updateMixingParams:self.shouldMixStream];
//    } else {
//        if (!self.memberManager.anchors[userId]) {
//            [self addTempAnchor:userId];
//        }
//        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
//            [self.delegate trtcLiveRoom:self onAnchorEnter:userId];
//        }
//    }
}
- (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
    [self logApi:@"onremoteUserLeaveRoom", userId, nil];
//    if (self.shouldPlayCdn) {
//        return;
//    }
//    if (self.isOwner) {
//        if (self.memberManager.anchors[userId] && self.memberManager.anchors.count <= 2) {
//            if (self.inviteAnchorInfo.userId && self.inviteAnchorInfo.userId == userId) {
//                if ([self canDelegateResponseMethod:@selector(trtcLiveRoomOnQuitInviteAnchor:)]) {
//                    [self.delegate trtcLiveRoomOnQuitInviteAnchor:self];
//                }
//            }
//            [self clearInviteState];
//            [self clearJoinState];
//            self.status = TRTCLiveRoomLiveStatusSingle;
//        }
//        [self.memberManager removeAnchor:userId];
//    }
//
//    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorExit:)]) {
//        [self.delegate trtcLiveRoom:self onAnchorExit:userId];
//    }
//    if (self.isOwner) {
//        [self.trtcAction updateMixingParams:self.shouldMixStream];
//    }
}

- (void)onFirstVideoFrame:(NSString *)userId streamType:(TRTCVideoStreamType)streamType width:(int)width height:(int)height {
    [self.trtcAction onFirstVideoFrame:userId];
}

#pragma mark - TRTCLiveRoomMembermanagerDelegate
- (void)memberManager:(TRTCLiveRoomMemberManager *)manager onUserEnter:(TRTCLiveUserInfo *)user isAnchor:(BOOL)isAnchor {
    if (isAnchor) {
        if (self.configCdn && [self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
            [self.delegate trtcLiveRoom:self onAnchorEnter:user.userId];
        }
    } else {
        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAudienceEnter:)]) {
            [self.delegate trtcLiveRoom:self onAudienceEnter:user];
        }
    }
}

- (void)memberManager:(TRTCLiveRoomMemberManager *)manager onUserLeave:(TRTCLiveUserInfo *)user isAnchor:(BOOL)isAnchor {
    if (isAnchor) {
        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorExit:)]) {
            [self.delegate trtcLiveRoom:self onAnchorExit:user.userId];
        }
    } else {
        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAudienceExit:)]) {
            [self.delegate trtcLiveRoom:self onAudienceExit:user];
        }
    }
}

- (void)memberManager:(TRTCLiveRoomMemberManager *)manager onChangeStreamId:(NSString *)streamID userId:(NSString *)userId {
    if (self.shouldPlayCdn) {
        return;
    }
    if (self.shouldMixStream && ![self.ownerId isEqualToString:userId]) {
        return;
    }
    if (streamID && ![streamID isEqualToString:@""]) {
        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
            [self.delegate trtcLiveRoom:self onAnchorEnter:userId];
        }
    } else {
        if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorExit:)]) {
            [self.delegate trtcLiveRoom:self onAnchorExit:userId];
        }
    }
}

- (void)memberManager:(TRTCLiveRoomMemberManager *)manager onChangeAnchorList:(NSArray<NSDictionary<NSString *,id> *> *)anchorList {
    if (!self.isOwner) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        return;
    }
    NSDictionary *data = @{
        @"type": @(self.status),
        @"list": anchorList,
    };
    [TRTCLiveRoomIMAction updateGroupInfoWithRoomID:roomID groupInfo:data callback:nil];
}
-(void)memberManager:(TRTCLiveRoomMemberManager *)manager onChangeRequestJoinAnchorList:(NSMutableDictionary<NSString *,TRTCLiveUserInfo *> *)requestJoinAnchorList{
    DDLogInfo(@"----------%@-------",requestJoinAnchorList);
    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onChangeRequestJoinAnchorList:)]) {
        [self.delegate trtcLiveRoom:self onChangeRequestJoinAnchorList:requestJoinAnchorList.allValues];
    }
}

#pragma mark - V2TIMAdvancedMsgListener
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
    if (msg.elemType == V2TIM_ELEM_TYPE_CUSTOM) {
        V2TIMCustomElem *elem = msg.customElem;
        NSData *data = elem.data;
        NSError *error;
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
        if (error) {
            return;
        }
        NSNumber* action = json[@"action"] ?: @(0);
        id version = json[@"version"] ?: @"";
        BOOL isString = [version isKindOfClass:[NSString class]];
        if (isString && ![version isEqualToString:trtcLiveRoomProtocolVersion]) {
            // 处理兼容性问题
        }
        [self handleActionMessage:[action intValue] elem:elem message:msg json:json];
    } else if (msg.elemType == V2TIM_ELEM_TYPE_TEXT) {
        if (msg.textElem) {
            [self handleActionMessage:TRTCLiveRoomIMActionTypeRoomTextMsg elem:msg.textElem message:msg json:@{}];
        }
    }
}

- (void)handleActionMessage:(TRTCLiveRoomIMActionType)action elem:(V2TIMElem *)elem message:(V2TIMMessage *)message json:(NSDictionary<NSString *, id> *)json {
    NSDate* sendTime = message.timestamp;
    // 超过10秒默认超时
    if (sendTime && sendTime.timeIntervalSinceNow < -10) {
        return;
    }
    NSString *userID = message.sender;
    if (!userID) {
        return;
    }
    TRTCLiveUserInfo *liveUser = [[TRTCLiveUserInfo alloc] init];
    liveUser.userId = userID;
    liveUser.userName = message.nickName ?: @"";
    liveUser.avatarURL = message.faceURL ?: @"";
    if (!self.memberManager.anchors[liveUser.userId]) {
        // 非主讲，更新观众列表
        if (action != TRTCLiveRoomIMActionTypeRequestInviteAnchor &&
            action != TRTCLiveRoomIMActionTypeRespondInviteAnchor &&
            action != TRTCLiveRoomIMActionTypeQuitInviteAnchor && action != TRTCLiveRoomIMActionTypeKickoutInviteAnchor) {
             [self.memberManager addAudience:liveUser];
        }
    }
    switch (action) {
        case TRTCLiveRoomIMActionTypeRequestJoinAnchor:
        {
            self.joinAnchorInfo.userId = userID;
            self.joinAnchorInfo.uuid = [[NSUUID UUID] UUIDString];
            [self.memberManager addRequestJoinAnchor:liveUser];
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRequestJoinAnchor:reason:timeout:)]) {
                [self.delegate trtcLiveRoom:self onRequestJoinAnchor:liveUser reason:json[@"reason"] ?: @"" timeout:trtcLiveHandleMsgTimeOut];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeRespondJoinAnchor:
        {
            NSNumber *agreedNum = json[@"accept"];
            BOOL agreed = [agreedNum boolValue];
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onResponseJoinAnchor:agreed:)]) {
                [self.delegate trtcLiveRoom:self onResponseJoinAnchor:liveUser agreed:agreed];
            }
    
            if (agreed) {
                [self startToAnchor:self.me.userId streamId:self.me.userId];
//                [self switchRole:YES];
//                NSString *uuid = self.joinAnchorInfo.uuid;
//                @weakify(self)
//                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(trtcLiveCheckStatusTimeOut * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//                    @strongify(self)
//                    if (!self) {
//                        return;
//                    }
//                    if (self.memberManager.anchors[userID] == nil && [uuid isEqualToString:self.joinAnchorInfo.uuid]) {
//                        [self kickoutJoinAnchor:userID callback:nil];
//                        [self clearJoinState:YES];
//                    } else {
//                        [self clearJoinState:NO];
//                    }
//                });
            } else {
                [self clearJoinState];
            }
            NSString *reason = json[@"reason"] ?: @"";
            if (self.requestJoinAnchorCallback) {
                self.requestJoinAnchorCallback(agreed, reason);
                self.requestJoinAnchorCallback = nil;
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeKickoutJoinAnchor:
        {
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoomOnKickoutJoinAnchor:)]) {
                [self.delegate trtcLiveRoomOnKickoutJoinAnchor:self];
            }
            // 收消息的人
            [self.memberManager removeRequestJoinAnchor:self.me.userId];
            [self stopCameraPreview];
            [self switchRole:NO];
            [self stopToAnchor:self.me.userId];
            [self clearJoinState:YES];
        }
            break;
        case TRTCLiveRoomIMActionTypeQuitJoinAnchor:{
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoomOnQuitJoinAnchor:leaveUser:)]) {
                [self.delegate trtcLiveRoomOnQuitJoinAnchor:self leaveUser:liveUser];
            }
            // 发消息的人
            [self.memberManager removeRequestJoinAnchor:userID];
            [self stopToAnchor:userID];
        }
            break;
        case TRTCLiveRoomIMActionTypeNotifyJoinAnchorStream:
        {
            // 普通观众收到消息  视频流切换到某个人了
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:StreamToAnchor:)]) {
                [self.delegate trtcLiveRoom:self StreamToAnchor:liveUser];
            }
        }
            break;
        case  TRTCLiveRoomIMActionTypeRequestInviteAnchor:
        {
            if (self.inviteAnchorInfo.userId != nil || self.status == TRTCLiveRoomLiveStatusInviteAnchor) {
                DDLogInfo(@"已经有主讲了");
                return ;
            }
            self.inviteAnchorInfo.userId = self.me.userId;
            self.inviteAnchorInfo.uuid = [[NSUUID UUID] UUIDString];
            [self.memberManager prepaerInviteAnchor:liveUser];
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:OnRequestInviteAnchor:timeout:)]) {
                [self.delegate trtcLiveRoom:self OnRequestInviteAnchor:liveUser timeout:trtcLiveCheckStatusTimeOut];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeRespondInviteAnchor:
        {
            NSNumber *agreedNum = json[@"accept"];
            BOOL agreed = [agreedNum boolValue];
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:OnResponseInviteAnchor:agreed:)]) {
                [self.delegate trtcLiveRoom:self OnResponseInviteAnchor:liveUser agreed:agreed];
            }
            if (agreed) {
                [self.memberManager confirmInviteAnchor:liveUser.userId];
            }else{
                //
                [self clearInviteState];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeQuitInviteAnchor:
        {
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoomOnQuitInviteAnchor:)]) {
                [self.delegate trtcLiveRoomOnQuitInviteAnchor:self];
            }
            [self clearInviteState];
        }
            break;
        case TRTCLiveRoomIMActionTypeKickoutInviteAnchor:{
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoomOnKickoutInviteAnchor:)]) {
                [self.delegate trtcLiveRoomOnKickoutInviteAnchor:self];
            }
            // 收消息的人
            [self clearInviteState];
            [self stopCameraPreview];
            [self switchRole:NO];
        }
            break;
        case TRTCLiveRoomIMActionTypeFeedbackInfo:{
            NSNumber* feedbackInfo = json[@"feedInfo"] ?: @(0);
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:feedInfo:)]) {
                [self.delegate trtcLiveRoom:self feedInfo:[feedbackInfo intValue]];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeRoomTextMsg:
        {
            V2TIMTextElem *textElem = (V2TIMTextElem *)elem;
            NSString *text = textElem.text;
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRecvRoomTextMsg:fromUser:)]) {
                [self.delegate trtcLiveRoom:self onRecvRoomTextMsg:text fromUser:liveUser];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeRoomCustomMsg:
        {
            NSString *command = json[@"command"];
            NSString *message = json[@"message"];
            if (command && message) {
                if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRecvRoomCustomMsgWithCommand:message:fromUser:)]) {
                    [self.delegate trtcLiveRoom:self onRecvRoomCustomMsgWithCommand:command message:message fromUser:liveUser];
                }
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeKickOutAudience:
        {
            // 收到消息的人弹框，然后退出直播间
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:beKickoutUser:)]) {
                [self.delegate trtcLiveRoom:self beKickoutUser:self.me];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeUpdateGroupInfo:
        {
            [self.memberManager updateAnchorsWithGroupinfo:json];
            NSNumber *roomStatus = json[@"type"];
            if (roomStatus != nil) {
                self.status = [roomStatus intValue];
            }
        }
            break;
        case TRTCLiveRoomIMActionTypeUnknown:
            DDLogInfo(@"收到了其他消息");
            break;
        default:
            TRTCLog(@"!!!!!!!! 未知消息type");
            break;
    }
}

#pragma mark - V2TIMGroupListener
- (void)onMemberInvited:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray<V2TIMGroupMemberInfo *> *)memberList {
    for (V2TIMGroupMemberInfo *member in memberList) {
        TRTCLiveUserInfo *user = [[TRTCLiveUserInfo alloc] init];
        user.userId = member.userID;
        user.userName = member.nickName ?: @"";
        user.avatarURL = member.faceURL ?: @"";
        [self.memberManager addAudience:user];
    }
}

- (void)onMemberLeave:(NSString *)groupID member:(V2TIMGroupMemberInfo *)member {
    [self.memberManager removeMember:member.userID];
}

- (void)onMemberEnter:(NSString *)groupID memberList:(NSArray<V2TIMGroupMemberInfo *> *)memberList {
    for (V2TIMGroupMemberInfo *member in memberList) {
        TRTCLiveUserInfo *user = [[TRTCLiveUserInfo alloc] init];
        user.userId = member.userID;
        user.userName = member.nickName ?: @"";
        user.avatarURL = member.faceURL ?: @"";
        [self.memberManager addAudience:user];
    }
}

- (void)onGroupInfoChanged:(NSString *)groupID changeInfoList:(NSArray<V2TIMGroupChangeInfo *> *)changeInfoList {
    __block V2TIMGroupChangeInfo *info = nil;
    [changeInfoList enumerateObjectsUsingBlock:^(V2TIMGroupChangeInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.type == V2TIM_GROUP_INFO_CHANGE_TYPE_INTRODUCTION) {
            info = obj;
            *stop = YES;
        }
    }];
    if (info) {
        NSDictionary *customInfo = [info.value mj_JSONObject];
        NSNumber *roomStatus = customInfo[@"type"];
        self.status = [roomStatus intValue];
    }
}

- (void)onGroupDismissed:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser {
    [self handleRoomDismissed:YES];
}

- (void)onRevokeAdministrator:(NSString *)groupID opUser:(V2TIMGroupMemberInfo *)opUser memberList:(NSArray<V2TIMGroupMemberInfo *> *)memberList {
    [self handleRoomDismissed:YES];
}


#pragma mark - Actions
- (void)notifyAvailableStreams {
    if (self.shouldMixStream) {
        if (self.ownerId && [self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
            [self.delegate trtcLiveRoom:self onAnchorEnter:self.ownerId];
        }
    } else {
        [self.memberManager.anchors.allKeys enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorEnter:)]) {
                [self.delegate trtcLiveRoom:self onAnchorEnter:obj];
            }
        }];
    }
}

- (void)handleRoomDismissed:(BOOL)isOwnerDeleted {
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        return;
    }
    if (self.isOwner && !isOwnerDeleted) {
        [self destroyRoom:nil];
    } else {
        [self exitRoom:nil];
    }
    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRoomDestroy:)]) {
        [self.delegate trtcLiveRoom:self onRoomDestroy:roomID];
    }
}

- (void)handleJoinAnchorRequestFromUser:(TRTCLiveUserInfo *)user reason:(NSString *)reason {
//    if (self.joinAnchorInfo.userId != nil) {
//        if (![self.joinAnchorInfo.userId isEqualToString:user.userId]) {
//            [self responseJoinAnchor:user.userId agree:NO reason:@"主播正在处理他人连麦中"];
//        }
//        return;
//    }
    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onRequestJoinAnchor:reason:timeout:)]) {
        [self.delegate trtcLiveRoom:self onRequestJoinAnchor:user reason:reason timeout:trtcLiveHandleMsgTimeOut];
    }
    
    [self.memberManager addRequestJoinAnchor:user];
   
    self.joinAnchorInfo.userId = user.userId;
    self.joinAnchorInfo.uuid = [[NSUUID UUID] UUIDString];
//    NSString *uuid = [self.joinAnchorInfo.uuid mutableCopy];
//    @weakify(self)
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(trtcLiveHandleMsgTimeOut * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//        @strongify(self)
//        if (!self) {
//            return;
//        }
//        if (!self.joinAnchorInfo.isResponsed && [uuid isEqualToString:self.joinAnchorInfo.uuid]) {
//            [self responseJoinAnchor:user.userId agree:YES reason:@"超时未回应"];
////            [self clearJoinState];
//        }
//    });
}

- (void)startToAnchor:(NSString *)userId streamId:(NSString *)streamId {
    self.status = TRTCLiveRoomLiveStatusLinkMic;
    [self.memberManager switchMember:userId toAnchor:YES streamId:streamId];
}

- (void)stopToAnchor:(NSString *)userId {
    self.status = self.memberManager.anchors.count <= 2 ? TRTCLiveRoomLiveStatusSingle : TRTCLiveRoomLiveStatusLinkMic;
    [self.memberManager switchMember:userId toAnchor:NO streamId:nil];
}

- (void)switchRole:(BOOL)isLinkMic {
    TRTCLiveUserInfo *me = [self checkUserLogIned:nil];
    if (!me) {
        return;
    }
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        return;
    }
    if (!isLinkMic) {
        [self.trtcAction switchRole:TRTCRoleAudience];
    }else{
        [self.trtcAction switchRole:TRTCRoleAnchor];
    }
    [TRTCLiveRoomIMAction notifyStreamToAnchorWithUserId:me.userId RoomID: roomID streamID:me.userId callback:^(int code, NSString * _Nonnull message) {

    }];
    
//    if (self.configCdn && self.shouldMixStream && !isLinkMic) {
//        [self.memberManager.anchors enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, TRTCLiveUserInfo * _Nonnull obj, BOOL * _Nonnull stop) {
//            if ([key isEqualToString:self.ownerId] && [self.trtcAction isUserPlaying:key]) {
//                if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onAnchorExit:)]) {
//                    [self.delegate trtcLiveRoom:self onAnchorExit:key];
//                }
//            }
//        }];
//    }
//    // 将播放流进行切换
//    if (self.configCdn) {
//        BOOL usesCDN = !isLinkMic;
//        [self.trtcAction togglePlay:usesCDN];
//    }
}
- (void)clearInviteState{
    [self.inviteAnchorInfo reset];
    [self.memberManager removeInviteAnchor];
}
- (void)clearJoinState {
    [self clearJoinState:YES];
}

- (void)clearJoinState:(BOOL)shouldRemove {
    if (shouldRemove && self.joinAnchorInfo.userId) {
        [self.memberManager removeAnchor:self.joinAnchorInfo.userId];
    }
    [self.joinAnchorInfo reset];
}


/// 观众连麦后，添加的临时主播
/// @param userId 主播ID
- (void)addTempAnchor:(NSString *)userId {
    TRTCLiveUserInfo *user = [[TRTCLiveUserInfo alloc] init];
    user.userId = userId;
    [self.memberManager addAnchor:user];
}

///// 预先保存待PK的主播，等收到视频流后，再确认PK状态
///// @param user 主播
///// @param streamId 流id
//- (void)prepareRoomPKWithUser:(TRTCLiveUserInfo *)user streamId:(NSString *)streamId {
//    user.streamId = streamId;
//    [self.memberManager prepaerPKAnchor:user];
//}

//// 发起PK的主播，收到确认回复后，调到该函数开启跨房PK
//- (void)startRoomPKWithUser:(TRTCLiveUserInfo *)user streamId:(NSString *)streamId {
//    NSString *roomId = self.pkAnchorInfo.roomId;
//    if (!roomId) {
//        return;
//    }
//    [self prepareRoomPKWithUser:user streamId:streamId];
//    [self.trtcAction startRoomPK:roomId userId:user.userId];
//}

#pragma mark - Beauty
- (void)setFilter:(UIImage *)image {
    [self.trtcAction setFilter:image];
}

- (void)setFilterConcentration:(float)concentration {
    [self.trtcAction setFilterConcentration:concentration];
}

- (void)setGreenScreenFile:(NSURL *)fileUrl {
    [self.trtcAction setGreenScreenFile:fileUrl];
}

#pragma mark - Utils
- (void)logApi:(NSString *)api, ... NS_REQUIRES_NIL_TERMINATION {
    
}

- (TRTCLiveUserInfo *)checkUserLogIned:(Callback)callback {
    if (!self.me) {
        if (callback) {
            callback(-1, @"还未登录");
        }
        return nil;
    }
    return self.me;
}

- (NSString *)checkRoomJoined:(Callback)callback {
    if (!self.roomID) {
        if (callback) {
            callback(-1, @"还未进入房间");
        }
        return nil;
    }
    return self.roomID;
}

- (BOOL)checkRoomUnjoined:(Callback)callback {
    if (self.roomID) {
        if (callback) {
            callback(-1, @"当前在房间中");
        }
        return NO;
    }
    return YES;
}

- (BOOL)checkIsOwner:(Callback)callback {
    if (!self.isOwner) {
        if (callback) {
            callback(-1, @"只有主持人才能操作");
        }
        return NO;
    }
    return YES;
}

- (NSString *)checkIsPublishing:(Callback)callback {
    if (!self.me.streamId) {
        if (callback) {
             callback(-1, @"只有推流后才能操作");
        }
        return nil;
    }
    return self.me.streamId;
}

- (void)reset {
    self.exitRoomCallback = nil;
    self.enterRoomCallback = nil;
    [self.trtcAction exitRoom];
    [self.trtcAction stopAllPlay:self.shouldPlayCdn];
    self.trtcAction.roomId = nil;
    self.status = TRTCLiveRoomLiveStatusNone;
    [self clearInviteState];
    [self clearJoinState];
    [self.memberManager clearMembers];
    self.curRoomInfo = nil;
    [self.eduBoard resetBoard];
}

-(void)exitLiveRoom{
    self.exitRoomCallback = nil;
    self.enterRoomCallback = nil;
    [self.trtcAction exitRoom];
    [self.trtcAction stopAllPlay:self.shouldPlayCdn];
    self.trtcAction.roomId = nil;
    self.status = TRTCLiveRoomLiveStatusNone;
    [self clearInviteState];
    [self clearJoinState];
    [self.memberManager clearMembers];
    self.curRoomInfo = nil;
    [self.eduBoard resetBoard];
}

#pragma mark - private readOnly property
- (BOOL)isOwner {
    if (self.me.userId) {
        return [self.me.userId isEqualToString:self.memberManager.ownerId];
    }
    return NO;
}

- (BOOL)isAnchor {
    if (self.me.userId) {
        return self.memberManager.anchors[self.me.userId] != nil;
    }
    return false;
}

- (BOOL)configCdn {
    return self.config.useCDNFirst;
}

- (BOOL)shouldPlayCdn {
    return self.configCdn && !self.isAnchor;
}

- (BOOL)shouldMixStream {
    switch (self.status) {
        case TRTCLiveRoomLiveStatusNone:
            return NO;
        case TRTCLiveRoomLiveStatusSingle:
            return NO;
        case TRTCLiveRoomLiveStatusLinkMic:
            return self.mixingLinkMicStream;
        case TRTCLiveRoomLiveStatusInviteAnchor:
            return self.mixingInviteAnchorStream;
        default:
            break;
    }
    return NO;
}

-(void)startShareEduBoardWithUserID:(NSString *)userID callback:(Callback)callback{
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        callback(-1,@"roomID 不能为 nil");
        return;
    }
    self.eduBoard.delegate = self;
    [self.eduBoard startBoardSharingWithRoomID:[roomID intValue]];
}

-(void)endShareEduBoardWithUserID:(NSString *)userID callback:(Callback)callback{
    NSString *roomID = [self checkRoomJoined:nil];
    if (!roomID) {
        callback(-1,@"roomID 不能为 nil");
        return;
    }
    [self.eduBoard resetBoard];
}

// 撤销
-(void)undoBoard{
    [self.eduBoard undoBoard];
}

// 恢复
-(void)redoBoard{
    [self.eduBoard redoBoard];
}

-(void)setBoardToolTypePen{
    [self.eduBoard setBoardToolTypePen];
}

-(void)setBoardToolTypeEraser{
    [self.eduBoard setBoardToolTypeEraser];
}

-(void)addTranscodeFileWithPages:(NSInteger)pages url:(NSString *)url title:(NSString *)title resolution:(NSString *)resolution{
    [self.eduBoard addTranscodeFileWithPages:pages url:url title:title resolution:resolution];
}

-(void)trtcLiveRoomEduBoard:(TRTCLiveRoomEduBoard *)eduBoard onTEBHistroyDataSyncCompleted:(UIView *)renderView{
    if ([self canDelegateResponseMethod:@selector(trtcLiveRoom:onTEBHistroyDataSyncCompleted:)]) {
        [self.delegate trtcLiveRoom:self onTEBHistroyDataSyncCompleted:renderView];
    }
}
@end
